package com.hsj.demo.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hsj.demo.config.MyEndpointConfigure;
import com.hsj.demo.entity.ChatHistory;
import com.hsj.demo.entity.Notice;
import com.hsj.demo.entity.User;
import com.hsj.demo.entity.UserFriend;
import com.hsj.demo.service.ChatHistoryService;
import com.hsj.demo.service.NoticeService;
import com.hsj.demo.service.UserFriendService;
import com.hsj.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@RestController
@RequestMapping("/websocket")
@ServerEndpoint(value = "/websocket/{userId}", configurator = MyEndpointConfigure.class)
public class WebSocketServer {

    /**
     * 在线人数
     */
    private static int onlineCount = 0;

    /**
     * 在线用户的Map集合，key：用户名，value：Session对象
     */
    private static Map<Integer, Session> sessionMap = new HashMap<Integer, Session>();

    /**
     * 注入其他类（换成自己想注入的对象）
     */
    @Autowired
    private UserService userService;
    @Autowired
    private UserFriendService userFriendService;
    @Autowired
    private ChatHistoryService chatHistoryService;
    @Autowired
    private NoticeService noticeService;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId) {
        //在webSocketMap新增上线用户
        sessionMap.put(userId, session);

        //在线人数加加
        WebSocketServer.onlineCount++;
        User user = userService.findById(userId);
        //通知除了自己之外的所有人
        sendOnlineCount(session, "{'type':'onlineCount','onlineCount':" + WebSocketServer.onlineCount +
                ",username:'" + user.getUsername() +
                "',profilePhoto:'" + user.getProfilePhoto() +
                "',userId:'" + user.getId() + "'}");
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        //下线用户名
        Integer logoutUserName = 0;

        //从webSocketMap删除下线用户
        for (Map.Entry<Integer, Session> entry : sessionMap.entrySet()) {
            if (entry.getValue() == session) {
                sessionMap.remove(entry.getKey());
                logoutUserName = entry.getKey();
                break;
            }
        }
        //在线人数减减
        WebSocketServer.onlineCount--;

        //通知除了自己之外的所有人
        sendOnlineCount(session, "{'type':'onlineCount','onlineCount':" + WebSocketServer.onlineCount + ",username:'" + logoutUserName + "'}");
    }

    /**
     * 服务器接收到客户端消息时调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            System.out.println(message);
            //JSON字符串转 HashMap
            HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);

            //消息类型
            String type = (String) hashMap.get("type");

            //来源用户
            int sourceUserId = Integer.valueOf(hashMap.get("sourceUserId").toString());
            hashMap.put("sourceUserId", sourceUserId);
            //目标用户
            int targetUserId = Integer.valueOf(hashMap.get("targetUserId").toString());
            hashMap.put("targetUserId", targetUserId);

            //如果点击的是自己，那就是群聊
            if (sourceUserId==targetUserId) {
                //群聊
                groupChat(session,hashMap);
            } else {
                //私聊
                privateChat(session, targetUserId, hashMap);
            }

            //后期要做消息持久化

        } catch (IOException | EncodeException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 通知除了自己之外的所有人
     */
    private void sendOnlineCount(Session session, String message) {
        for (Map.Entry<Integer, Session> entry : sessionMap.entrySet()) {
            try {
                if (entry.getValue() != session) {
                    entry.getValue().getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 私聊
     */
    private void privateChat(Session session, int targetUserId, HashMap hashMap) throws IOException, EncodeException {
        //获取目标用户的session
        Session tarUserSession = sessionMap.get(targetUserId);
        //将这条消息添加到数据库
        ((HashMap)hashMap.get("chatHistory")).put("id",chatHistoryService.insert(hashMap).getId());
        //如果不在线则发送“对方不在线”回来源用户
        if (tarUserSession != null) {
            hashMap.put("type", "1");
            tarUserSession.getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
        }
        //session.getBasicRemote().sendObject();
    }

    /**
     * 群聊
     */
    private void groupChat(Session session,HashMap hashMap) throws IOException {
        for (Map.Entry<Integer, Session> entry : sessionMap.entrySet()) {
            //自己就不用再发送消息了
            if (entry.getValue() != session) {
                hashMap.put("type", "2");
                entry.getValue().getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
            }
        }
    }

    /**
     * 根据用户Id获取用户对象
     */
    @RequestMapping("/getUserById")
    public User getUserById(Integer userId){
        return userService.findById(userId);
    }

    @RequestMapping("/deleteById")
    public String deleteById(@RequestBody UserFriend userFriend, HttpSession session){
        User user = (User)session.getAttribute("user");
        sendNotice(userFriendService.deleteFriend(userFriend,user));
        return "删除成功";
    }

    @RequestMapping("/insertNotice")
    public String insertNotice(@RequestBody Map map,HttpSession session){
        Notice notice = noticeService.insertNotice(map,session);
        if(notice!=null){
            sendNotice(notice);
            return "发布成功";
        }else{
            return "发布失败";
        }
    }

    @RequestMapping("/addFriend")
    public String addFriend(@RequestBody UserFriend userFriend,HttpSession session){
        User user = (User)session.getAttribute("user");
        Notice notice = userFriendService.insertFriend(userFriend,user);
        if(notice==null){
            return "已添加该用户，不可重复添加！";
        }else{
            sendNotice(notice);return "好友请求已发送";
        }
    }

    private void sendNotice(Notice notice){
        try {
            HashMap<String,Object> hashMap = new HashMap<>();
            hashMap.put("type","3");
            // 给个人发消息，且在线
            if(notice.getTargetType()==0){
                for (Map.Entry<Integer, Session> entry : sessionMap.entrySet()) {
                    //自己就不用再发送消息了
                    if (entry.getKey() == notice.getTargetUserId()) {
                        hashMap.put("notice",notice);
                        entry.getValue().getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
                        break;
                    }
                }
            }else if(notice.getTargetType()==1){    //给全体在线用户发消息
                for (Map.Entry<Integer, Session> entry : sessionMap.entrySet()) {
                    hashMap.put("notice",notice);
                    entry.getValue().getBasicRemote().sendText(new ObjectMapper().writeValueAsString(hashMap));
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

}